/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 * */

// AmzServer - Tototoy's server model.
// Author: tonyjobmails@gmail.com (tonyhack).
//
// Define class Mutex.
//

#ifndef __MUTEX__H
#define __MUTEX__H

#include <string.h>
#include <pthread.h>

#include "logging.h"
#include "noncopyable.h"
#include "scoped_mutex.h"

namespace amz {

class Mutex : public noncopyable {
 public:
  typedef ScopedMutex<Mutex> AutoMutex;

  explicit Mutex(bool recursive = true) {
    int return_value = 0;

    if(recursive) { 
      pthread_mutexattr_t attr;
      return_value = pthread_mutexattr_init(&attr);
      if(return_value == 0) {
        return_value = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
        if(return_value == 0)
          return_value = pthread_mutex_init(&this->mutex_, &attr);
        // Destroy mutex attribute variable.
        return_value = pthread_mutexattr_destroy(&attr);
      }
    } else {
      // Defualt is "PTHREAD_MUTEX_DEFAULT".
      return_value = pthread_mutex_init(&this->mutex_, NULL);
    }

    Mutex::ErrorLog("Mutex::Mutex", return_value);
  }
  ~Mutex() {
    Mutex::ErrorLog("Mutex::~Mutex", pthread_mutex_destroy(&this->mutex_));
  }

  inline void Lock() {
    Mutex::ErrorLog("Mutex::Lock", pthread_mutex_lock(&this->mutex_));
  }
  inline void Unlock() {
    Mutex::ErrorLog("Mutex::Unlock", pthread_mutex_unlock(&this->mutex_));
  }

 private:
  static void ErrorLog(const char* context, int error) {
    if(error != 0) {
      LOG(ERROR) << context
                 << " error:"
                 << strerror(error);
    }
  }

  pthread_mutex_t mutex_;

  friend class ConditionVariable;
};

}  // namespace amz

#endif  // __MUTEX__H

